﻿using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Diagnostics;
using System.Reflection;
using System.Windows;
using System.Windows.Input;
using CredentialsManager.Common;
using CredentialsManager.Helpers;
using CredentialsManager.Properties;
using MVVMFoundation;

namespace CredentialsManager.ViewModels
{
    public class ApplicationListViewModel : ViewModelBase
    {   
        #region Private member variables

        private ReadOnlyCollection<string> m_Applications;
        private string m_SelectedApplication;

        private RelayCommand m_RefreshApplicationsCommand;
        private RelayCommand m_DeleteApplicationCommand;
        private RelayCommand m_CreateApplicationCommand;

        private BackgroundWorker m_DeleteWorker;

        #endregion

        #region Constructors

        public ApplicationListViewModel()
            : base()
        {
            m_DeleteWorker = new BackgroundWorker();
            m_DeleteWorker.DoWork += m_DeleteWorker_DoWork;
            m_DeleteWorker.RunWorkerCompleted += m_DeleteWorker_RunWorkerCompleted;

            var proxy = ProxyFactory.Create<ApplicationManagerClient, IApplicationManager>(ServiceAddressList.CredentialsService);

            try
            {
                var applications = proxy.GetApplications();
                Debug.Assert(applications != null);
                this.Applications = new ReadOnlyCollection<string>(applications);

                if (this.Applications != null && this.Applications.Count > 0)
                {
                    this.SelectedApplication = this.Applications[0];
                    return;
                }
            }
            finally
            {
                ProxyFactory.Cleanup<ApplicationManagerClient, IApplicationManager>(proxy);
            }
        }

        public ApplicationListViewModel(string displayName)
            : this()
        {
            this.DisplayName = displayName;
        }

        #endregion

        #region Background worker handlers

        private void m_DeleteWorker_DoWork(object sender, DoWorkEventArgs e)
        {
            Debug.Assert(e.Argument != null);
            string application = e.Argument.ToString();

            var proxy = ProxyFactory.Create<ApplicationManagerClient, IApplicationManager>(
                ServiceAddressList.CredentialsService);

            try
            {
                proxy.DeleteApplication(application);
            }
            finally
            {
                ProxyFactory.Cleanup<ApplicationManagerClient, IApplicationManager>(proxy);
            }
        }

        private void m_DeleteWorker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
        {
            if (e.Error != null)
            {
                ErrorHandler.HandleNonSpecificWCFException(e.Error, this.DisplayName);
            }

            this.IsLoading = false;

            if (e.Error == null)
            {
                IMessageBoxService messageBox = base.GetService<IMessageBoxService>();
                Debug.Assert(messageBox != null);

                string message = string.Format(Resources.ApplicationDeletedSuccessMessage.ToString(),
                    this.SelectedApplication);

                messageBox.Show(message, this.DisplayName,
                    MessageBoxButton.OK, MessageBoxImage.Information);

                RefreshApplications();
            }
        }

        #endregion

        #region Public properties

        public ReadOnlyCollection<string> Applications
        {
            get
            {
                return m_Applications;
            }
            private set
            {
                m_Applications = value;
                RaisePropertyChanged(MethodBase.GetCurrentMethod().GetPropertyName());
            }
        }

        public string SelectedApplication
        {
            get
            {
                return m_SelectedApplication;
            }
            set
            {
                m_SelectedApplication = value;
                RaisePropertyChanged(MethodBase.GetCurrentMethod().GetPropertyName());
                Mediator.NotifyColleagues<string>(MediatorMessages.SelectedApplicationChanged, 
                    m_SelectedApplication);
            }
        }

        #endregion

        #region Private methods

        private void CreateApplication()
        {
            var createApplicationDialog = base.GetService<IDialogService>();
            Debug.Assert(createApplicationDialog != null);

            var applicationViewModel = new ApplicationViewModel(this.Applications);
            createApplicationDialog.ShowModal(applicationViewModel);

            string selectedApplication = this.SelectedApplication;
            this.Applications = new ReadOnlyCollection<string>(applicationViewModel.Applications);

            if (selectedApplication == null && this.Applications.Count > 0)
            {
                selectedApplication = this.Applications[0];
            }

            this.SelectedApplication = selectedApplication;
        }

        private void DeleteApplication()
        {
            if (!string.IsNullOrEmpty(this.SelectedApplication))
            {
                IMessageBoxService messageBox = base.GetService<IMessageBoxService>();
                Debug.Assert(messageBox != null);

                string message = string.Format(Resources.ConfirmApplicationDeletionMessage.ToString(),
                    this.SelectedApplication);

                MessageBoxResult result = messageBox.Show(message, this.DisplayName,
                    MessageBoxButton.YesNo, MessageBoxImage.Question);

                if (result == MessageBoxResult.Yes)
                {
                    this.IsLoading = true;
                    this.ProgressMessage = string.Format(
                        Resources.DeletingApplicationProgressMessage.ToString(), 
                        this.SelectedApplication);
                    Mediator.NotifyColleagues<string>(MediatorMessages.ProgressMessageChanged, this.ProgressMessage);
                    m_DeleteWorker.RunWorkerAsync(this.SelectedApplication);
                }
            }
        }

        private void RefreshApplications()
        {
            Mediator.NotifyColleagues<object>(MediatorMessages.RefreshApplicationList, null);
        }

        #endregion

        #region Commands

        public ICommand CreateApplicationCommand
        {
            get
            {
                return m_CreateApplicationCommand ?? (m_CreateApplicationCommand = new RelayCommand(
                    param => this.CreateApplication()));
            }
        }

        public ICommand DeleteApplicationCommand
        {
            get
            {
                return m_DeleteApplicationCommand ?? (m_DeleteApplicationCommand = new RelayCommand(
                    param => this.DeleteApplication()));
            }
        }

        public ICommand RefreshApplicationsCommand
        {
            get
            {
                return m_RefreshApplicationsCommand ?? (m_RefreshApplicationsCommand = new RelayCommand(
                    param => this.RefreshApplications()));
            }
        }

        #endregion
    }
}
